package org.example.rzfx.aspect;

import cn.dev33.satoken.stp.StpUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.example.rzfx.annotation.OperationLog;
import org.example.rzfx.entity.User;
import org.example.rzfx.service.OpLogService;
import org.example.rzfx.service.UserService;
import org.example.rzfx.util.IpUtil;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * 操作日志AOP切面
 */
@Aspect
@Component
@Slf4j
public class OperationLogAspect {
    
    @Resource
    private OpLogService opLogService;
    
    @Resource
    private UserService userService;
    
    @Pointcut("@annotation(org.example.rzfx.annotation.OperationLog)")
    public void operationLogPointcut() {
    }
    
    @Around("operationLogPointcut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long startTime = System.currentTimeMillis();
        
        // 执行方法
        Object result = point.proceed();
        
        // 记录操作日志
        try {
            recordOperationLog(point, System.currentTimeMillis() - startTime);
        } catch (Exception e) {
            log.error("记录操作日志失败", e);
        }
        
        return result;
    }
    
    /**
     * 记录操作日志
     */
    private void recordOperationLog(ProceedingJoinPoint point, long executeTime) {
        try {
            // 获取注解信息
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            OperationLog annotation = method.getAnnotation(OperationLog.class);
            
            if (annotation == null) {
                return;
            }
            
            // 获取当前用户信息
            Long userId = null;
            String username = "anonymous";
            
            try {
                if (StpUtil.isLogin()) {
                    userId = StpUtil.getLoginIdAsLong();
                    User user = userService.getById(userId);
                    if (user != null) {
                        username = user.getUsername();
                    }
                }
            } catch (Exception e) {
                log.warn("获取用户信息失败", e);
            }
            
            // 获取请求IP
            String ip = "0.0.0.0";
            try {
                ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                if (attributes != null) {
                    HttpServletRequest request = attributes.getRequest();
                    ip = IpUtil.getIpAddress(request);
                }
            } catch (Exception e) {
                log.warn("获取请求IP失败", e);
            }
            
            // 构建操作描述
            String description = annotation.description();
            if (description.isEmpty()) {
                description = method.getName();
            }
            
            // 保存操作日志
            if (userId != null) {
                opLogService.saveOpLog(
                    userId,
                    username,
                    annotation.type(),
                    description + " (耗时: " + executeTime + "ms)",
                    ip
                );
            }
            
            log.info("操作日志记录成功: 用户[{}] 执行[{}] 操作: {}", username, annotation.type(), description);
            
        } catch (Exception e) {
            log.error("记录操作日志异常", e);
        }
    }
}

